#!/usr/bin/env python
#coding=utf-8

import re
import os
import time
import logging
from xsl import XLSWriter

from vic.exchange.vic_okex.okex_http import OkexHttp
from vic.exchange.vic_okex.okexft_http import OkexftHttp

from lib.common import config_data, log_info, log_exception, timestamp2str, \
     current_strtime, before_after_timestamp, get_symbol, config_error_code_msg

class OkexService(OkexHttp, OkexftHttp):
    """BinanService"""
    def __init__(self, url, apikey, apisecret):
        super(OkexService, self).__init__(url, apikey, apisecret)
        self.url       = url
        self.apiKey    = apikey
        self.apiSecret = apisecret
        self.msg       = {}
        self.http      = OkexHttp(url, apikey, apisecret)
        self.ft_http   = OkexftHttp(url, apikey, apisecret)

    def future_userinfo(self):
        """获取OKEx合约账户信息(全仓)"""
        future_userinfo = self.ft_http.future_userinfo()['info']
        return future_userinfo

    def funds(self):
        """okex用户资金"""

        userinfo = self.http.userinfo()

        try:
            funds = userinfo['info']['funds']
        except Exception as e:
            logging.exception('### error', e)
            raise e

        return funds

    def free_data(self):
        """okex可用币种数据资料"""

        funds = self.funds()
        free = funds['free']

        return free

    def freezed_data(self):
        """okex冻结币种数据资料"""

        funds = self.funds()
        freezed = funds['freezed']

        return freezed

    def borrow_data(self):
        """okex已借币种数据资料"""

        funds = self.funds()
        borrow = funds['borrow']

        return borrow

    def currency_balance(self, free_data, freezed_data, future_userinfo, currency):
        """okex币种余额"""

        balance, free, freezed, account_rights = 0, 0, 0, 0
        if free_data.get(currency):
            free = float(free_data[currency])

        if freezed_data.get(currency):
            freezed = float(freezed_data[currency])

        userinfo = future_userinfo.get(currency)  # 全仓信息
        if userinfo:
            account_rights = float(userinfo.get('account_rights'))

        balance = free + freezed + account_rights

        return balance

    def currency_list(self):
        """币种列表"""

        funds         = self.funds()
        free_data     = funds['free']
        freezed_data  = funds['freezed']
        future_userinfo = self.future_userinfo()

        _coin_list = []
        coin_list  = free_data.keys()
        for coin in coin_list:
            currency_balance = self.currency_balance(free_data,
                                                     freezed_data,
                                                     future_userinfo,
                                                     coin)
            if currency_balance > 0:
                coin.lower()
                _coin_list.append(coin) # 把币种转为小写字母

        return _coin_list


    def tousdt_rate(self, currency):
        """币安转usdt比率"""

        if currency == 'usdt':
            rate = 1
        else:
            p = self.http.ticker(currency+'_usdt')
            if p.get('error_code') == 1007:
                rate = 0
            else:
                rate = float(p['ticker']['last'])

        return rate


    def sum_usdt(self):
        """币安所有币种转usdt的总数"""

        sum = 0
        funds         = self.funds()
        free_data     = funds['free']
        freezed_data  = funds['freezed']
        future_userinfo = self.future_userinfo()

        currency_list = self.currency_list()
        for currency in currency_list:
            balance = self.currency_balance(free_data,
                                            freezed_data,
                                            future_userinfo,
                                            currency)

            sum += float(balance*self.tousdt_rate(currency))

        return sum


    def currency_tousdt(self, currency):
        """币种转usdt的值"""

        funds           = self.funds()
        free_data       = funds['free']
        freezed_data    = funds['freezed']
        future_userinfo = self.future_userinfo()

        balance = self.currency_balance(free_data,
                                        freezed_data,
                                        future_userinfo,
                                        currency)

        rate = self.tousdt_rate(currency)
        usdt = float(balance*rate)

        return usdt


    def okex_cancel_order(self, currency, to_currency):
        """okex币币一键撤单"""
        symbol = get_symbol(currency, to_currency, 'okex')
        # 订单id列表
        order_history = self.http.order_history(symbol)
        order_list    = order_history['orders']
        order_id_list = [order.get('order_id') for order in order_list]
        status_code = self.http.status_code
        if len(order_id_list) <= 0:
            log_info(u'%s:无单可撤!'% currency)

        for order_id in order_id_list:
            self.http.cancelorder(symbol, order_id)
            log_info(u'订单id为:%s, 撤单成功!'% order_id)
            time.sleep(0.5)
            self.error_msg_log()
        return True


    def error_msg_log(self):
        """获取错误码的信息"""
        json       = self.http.json
        error_code = json.get('error_code')
        file       = "../conf/okexws_error_code.txt"
        msg        = config_error_code_msg(error_code, file)
        if msg:
            log_info(msg)
            log_info('## json:%s'% json)
            return False
        return True


    def okex_future_cancel(self, currency, to_currency, contract_type):
        """okex取消合约订单"""

        symbol    = get_symbol(currency, to_currency, 'okex')
        # 订单id列表
        data = self.ft_http.future_order_info(symbol, contract_type, '-1')
        order_list    = data['orders'] if data.get('result') else[]
        order_id_list = [str(order.get('order_id')) for order in order_list]

        if len(order_id_list) <= 0:
            log_info(u'%s:无单可撤!'% currency)

        order_num = len(order_id_list)
        for num in range(order_num):
            order_id = order_id_list[num]
            print('### order_id:%s'% order_id)
            self.ft_http.future_cancel(symbol, contract_type, order_id)
            time.sleep(0.5) # 访问频率 4次/2秒
            log_info(u'订单id: %s, 撤单成功!'% order_id)

        return True


    def okex_cancel_allorder(self, currency='', file_name=''):
        """okex撤销所有能撤销的订单"""

        funds         = self.funds()
        free          = funds['free']
        freezed_data  = funds['freezed']
        currency_list = self.currency_list()
        taobao_list   = self.taobao_currency_list(file_name)

        for c in currency_list:
            if currency and c not in (currency.upper(), currency.lower()):
                continue # 过滤不是要撤销的币种

            if c == 'usdt':
                continue # 如果是usdt就循环下一个

            if c in taobao_list:
                continue # 套保的资金不清仓

            symbol      = get_symbol(c, 'usdt', 'okex')
            tousdt_list = self.conf_currency_tousdt_list()
            if c.upper() in tousdt_list:
                self.okex_cancel_order(c, 'usdt')
                self.okex_future_cancel(c, 'usdt', 'quarter')

        return True


    def symbol_latest_price(self, symbol):
        """symbol最新价格"""
        ticker     = self.http.ticker(symbol)['ticker']
        high_price = ticker['high']
        return high_price


    def symbol_order(self, symbol, quantity, tradetype='sell_market'):
        """symbol下单"""
        self.http.addorder(symbol, tradetype, 0, quantity) # 市价单不传价格
        if self.error_msg_log() is not False:
            log_info(u'%s 下单量:%s, 成功!'% (symbol, quantity))
        return True


    def account_order(self, quantity, currency='', multiple='', file=''):
        """账户下单"""
        tousdt_list = self.conf_currency_tousdt_list()
        if currency and currency in tousdt_list:
            symbol = get_symbol(currency, 'usdt', 'okex')
            self.symbol_order(symbol, quantity)
        else:
            currency_list = self.currency_list()
            taobao_list   = self.taobao_currency_list(file)

            # 币币账户信息
            for c in currency_list:
                if c == 'usdt':
                    continue # 如果是usdt就循环下一个

                if c in taobao_list:
                    continue # 套保的资金不清仓

                if currency and currency not in (c.upper(), c.lower()):
                    continue # 过滤掉不是指定的减仓币种

                symbol = get_symbol(c, 'usdt', 'okex')
                userinfo = self.ft_http.future_userinfo().get(c)  # 全仓信息
                if userinfo:
                    # 合约账户资金划转至币币账户
                    account_rights = float(userinfo.get('account_rights'))
                    self.ft_http.future_devolve(symbol, 2, account_rights)

                funds           = self.funds()
                # free            = funds['free']
                # freezed_data    = funds['freezed']
                # freezed_balance = freezed_data.get(c)
                # free_balance    = float(free.get(c))
                # if freezed_balance > 0:
                #     self.okex_cancel_order(c, 'usdt')
                #     funds = self.funds() # 撤销订单后,要重新获取账户信息
                #     time.sleep(1)

                free         = funds['free']
                free_balance = float(free.get(c))
                if free_balance > 0 and c.upper() in tousdt_list:
                    quantity = free_balance*float(multiple)
                    to_balance = free_balance - quantity
                    self.symbol_order(symbol, '%.2f' % quantity)
                    log_info(u'%s:递归下单开始'% symbol)
                    self.accounts_recursion(c, to_balance, currency_list)
                    log_info(u'%s:递归下单结束'% symbol)
        return True


    def conf_currency_tousdt_list(self):
        """获取配置文件币种转usdt的列表"""
        currency_tousdt_list = []
        file = "../conf/okex-market-channels.txt"
        with open(file, 'r') as f:
            data      = f.read()
            data      = data.replace('\r', '')
            data_list = data.split('\n')
            for d in data_list:
                d_list = re.split(r'[\-\,]+', d)
                if not d_list[0] or d_list[0] != 'OKEX' or d_list[2] != 'USDT':
                    continue # 不是BINA开头和USDT结尾的就循环下一个
                currency_tousdt_list.append(d_list[1])

        return currency_tousdt_list


    def taobao_currency_list(self, file):
        """套保列表"""
        file = '%s' % file
        taobao_list = []
        if not file:
            return taobao_list

        with open(file, 'r') as f:
            data      = f.read()
            data      = data.replace('\r', '')
            data_list = data.split('\n')
            for d in data_list:
                d_list = re.split(r'[\s\,]+', d)
                key   = d_list[0].lower()
                if key == c:
                    taobao_list.append(c)

        return taobao_list


    def accounts_recursion(self, currency, to_balance, currency_list):
        """账户递归"""
        time.sleep(3) # 休息3秒再递归
        self.okex_cancel_order(currency, 'usdt')
        self.okex_future_cancel(currency, 'usdt', 'quarter')
        for c in currency_list:
            if c != currency:
                continue
            funds        = self.funds()
            free         = funds['free']
            free_balance = float(free.get(c))
            diff_price   = free_balance - to_balance
            if diff_price > 0.01 and to_balance >= 0.005:
                symbol = get_symbol(c, 'usdt', 'okex')
                self.symbol_order(symbol, '%.2f' % diff_price)
                if self.error_msg_log() is True:
                    return self.accounts_recursion(currency,
                                                   to_balance,
                                                   currency_list)
        return True
